/*******************************************************************************
 * Copyright 2011 WaTho
 * 
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 * 
 *   http://www.apache.org/licenses/LICENSE-2.0
 * 
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 ******************************************************************************/
package de.wathoserver.android.dragoid.api;

import java.io.IOException;
import java.io.StringWriter;
import java.net.MalformedURLException;
import java.net.URL;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.regex.Pattern;

import org.apache.http.client.HttpClient;
import org.apache.http.client.ResponseHandler;
import org.apache.http.client.methods.HttpGet;
import org.apache.http.impl.client.BasicResponseHandler;
import org.apache.http.impl.client.DefaultHttpClient;
import org.htmlcleaner.CleanerProperties;
import org.htmlcleaner.HtmlCleaner;
import org.htmlcleaner.JDomSerializer;
import org.htmlcleaner.TagNode;
import org.htmlcleaner.XPatherException;
import org.jdom.Attribute;
import org.jdom.Content;
import org.jdom.Document;
import org.jdom.Element;
import org.jdom.JDOMException;
import org.jdom.output.Format;
import org.jdom.output.XMLOutputter;
import org.jdom.xpath.XPath;

import android.content.Context;
import android.content.SharedPreferences;
import android.preference.PreferenceManager;
import android.util.Log;
import android.webkit.URLUtil;
import de.wathoserver.android.dragoid.api.Building.BUILDING_TYPES;
import de.wathoserver.android.dragoid.api.StockItem.STOCK_TYPE;
import de.wathoserver.android.dragoid.util.RegexHelper;

/**
 * Realisiert das Laden und Parsen der html-Seiten von www.dragosien.de.
 * 
 * @author watho
 * 
 */
public class DragoApi implements DragoidConstants {

	private static final String TAB_URL_PATTERN = "&t=village&overview=%s";
	private static final String SINGLEBUILDING_URL = "http://www.dragosien.de/?request=%s&t=building&position=%s";
	private static final String TRANSFER_MATERIAL_URL = "http://www.dragosien.de/?request=%s&t=building&action=transfer_material&position=%s&product=%s&count=%s";
	private static final String WITHDRAW_MATERIAL_URL = "http://www.dragosien.de/?request=%s&t=building&action=getback_material&position=%s&product=%s";
	private static final String UPGRADE_BUILDING_URL = "http://www.dragosien.de/?request=%s&t=building&position=%s&action=%s";// &building=%s";

	public static final int VILLAGE_STOCK = 1;
	public static final int VILLAGE_PRODUCTION = 3;
	public static final int VILLAGE_MATERIAL = 4;
	public static final int VILLAGE_CONDITION = 8;
	public static final int VILLAGE_NOTICE = 5;

	private static DragoApi instance;

	private URL permanentLogin;
	private String tabUrl;
	private Pattern requestPattern;
	/** Sucht die Position in Strings wie ?t=building&position=17 */
	private Pattern posInRequestPattern;
	private String requestToken;
	static String lastError = "";
	private HttpClient client;

	private DragoApi(Context context) {
		Log.d(LOG_TAG, "Init DragoApi");
		SharedPreferences prefs = PreferenceManager
				.getDefaultSharedPreferences(context);
		String permanentLogin = prefs
				.getString("account_permanent_login", null);
		// Log.d(LOG_TAG, "loginurl = " + permanentLogin);
		try {
			if ((lastError = DragoApi.isValidPermanentLogin(permanentLogin)) == null) {
				this.permanentLogin = new URL(permanentLogin);
				this.tabUrl = this.permanentLogin.toString() + TAB_URL_PATTERN;
				// Log.d(LOG_TAG, "taburl = " + this.tabUrl);
			} else {
				Log.e(LOG_TAG, "ungültige loginurl = " + permanentLogin);
				this.permanentLogin = null;
				return;
			}
		} catch (MalformedURLException e) {
			Log.e(LOG_TAG, "Permanentlogin ungültig", e);
			this.permanentLogin = null;
			return;
		}
		// this.singleBuildingUrl = permanentLogin + SINGLEBUILDING_URL_PATTERN;
		requestPattern = Pattern
				.compile(
						".*var\\s*_TPL_SELF\\s*=\\s*'http://www.dragosien.de/.*request=(\\d*).*",
						Pattern.DOTALL);
		posInRequestPattern = Pattern.compile(".*\\?.*position=(\\d*)\\D*.*");
		client = new DefaultHttpClient();
	}

	/**
	 * Gibt die Singleton-Instanz zurück.
	 * 
	 * @return
	 * @throws IllegalAccessException
	 */
	public static DragoApi getApi() throws IllegalAccessException {
		if (instance == null || instance.permanentLogin == null) {
			throw new IllegalAccessException(
					String.format("Api not initialised."));
		}
		return instance;
	}

	/**
	 * Initialisiert den Datenzugriff. Wenn ein Fehler aufgetreten ist, kann er
	 * mit #getLastError() abgefragt werden.
	 * 
	 * @param context
	 */
	public static void initDragoApi(Context context) {
		instance = new DragoApi(context);
		if (instance.permanentLogin == null) {
			throw new IllegalArgumentException("Permanentlogin ungültig");
		}
	}

	/**
	 * Lädt Reiter L und parst den Lagerbestand.
	 * 
	 * @param showEmptyStocks
	 * @return
	 */
	@SuppressWarnings("unchecked")
	public List<Map<String, String>> getStockItems(boolean showEmptyStocks) {
		List<Map<String, String>> result = new ArrayList<Map<String, String>>();
		try {
			Element root = fetchTab(VILLAGE_STOCK);
			if (root == null) {
				return result;
			}
			List<Element> trs = XPath
					.selectNodes(root,
							"//table[@id='store']/tbody/tr[child::td/child::a[@class='inline']]");
			for (Element tr : trs) {
				// <tr>
				// <td><a class="inline"
				// href="?t=market&amp;product=alraune">Alraune:</a></td>
				// <td style="text-align: right;" class="green"
				// title="Noch Platz für 5084 Alraune">0<br></td>
				// </tr>
				List<Element> td = tr.getChildren("td");
				StockItem st = new StockItem(td.get(0).getChildTextTrim("a"));
				// zweiter Knoten ist direkt die Menge
				st.setNumber(Integer.valueOf(td.get(1).getTextTrim()
						.replace(".", "")));
				if (showEmptyStocks || st.getNumber() > 0) {
					result.add(st.toMap());
				}
			}
		} catch (JDOMException e) {
			e.printStackTrace();
		}
		return result;
	}

	/**
	 * Lädt Reiter P und parst die Produktion der Waren.
	 * 
	 * @return
	 */
	@SuppressWarnings("unchecked")
	public List<Map<String, String>> getStockItemsForProduction() {
		List<Map<String, String>> result = new ArrayList<Map<String, String>>();
		try {
			Element root = fetchTab(VILLAGE_PRODUCTION);
			if (root == null) {
				return result;
			}
			// <tr>
			// <td><a class="inline"
			// href="?t=market&amp;product=alraune">Alraune:</a>&nbsp;</td>
			// <td style="font-size: 10px;">0/0</td>
			// </tr>
			// Finde alle Zeilen mit einem Kindknoten <a class="inline">
			List<Element> res = XPath
					.selectNodes(root,
							"//table[@class='overview']/tbody/tr[child::td/child::a[@class='inline']]");
			String name = "";
			String production = "";
			for (Element tr : res) {
				List<Element> td = tr.getChildren("td");
				// erster Knoten ist <a>
				name = td.get(0).getChildTextTrim("a");
				// zweiter Knoten ist direkt die Menge
				production = td.get(1).getTextTrim();
				if (!"0/0".equals(production)) {
					StockItem st = new StockItem(name);
					st.setProduction(production);
					result.add(st.toMap());
				}
			}
		} catch (JDOMException e) {
			e.printStackTrace();
		}
		return result;
	}

	/**
	 * Lädt Reiter M und parst, wie lange die Materialien ausreichen.
	 * 
	 * @return
	 */
	@SuppressWarnings("unchecked")
	public List<Map<String, String>> getSuppliesTo() {
		List<Map<String, String>> result = new ArrayList<Map<String, String>>();
		try {
			Element root = fetchTab(VILLAGE_MATERIAL);
			if (root == null) {
				return result;
			}
			// XMLOutputter out = new XMLOutputter(Format.getPrettyFormat());
			// <tr>
			// <td><a class="inline"
			// href="?t=market&amp;product=alraune">Alraune:</a>&nbsp;</td>
			// <td style="font-size: 10px;">0/0</td>
			// </tr>
			// Finde alle Zeilen mit einem Kindknoten <a class="inline">
			List<Element> res = XPath
					.selectNodes(root,
							"//table[@class='overview']/tbody/tr[child::td/child::a[@class='inline']]");
			// String name = "";
			String supplies = "";
			int pos = -1;
			for (Object object : res) {
				Element tr = (Element) object;
				List<Element> td = tr.getChildren("td");
				// erster Knoten ist <a>
				// name = td.get(0).getChildTextTrim("a");
				// logHtml(td.get(0).getChild("a"));
				String posStr = RegexHelper.evalSingleGroupPattern(td.get(0)
						.getChild("a").getAttributeValue("href"),
						posInRequestPattern);
				try {
					pos = Integer.valueOf(posStr);
					// zweiter Knoten ist direkt die Zeit
					supplies = td.get(1).getTextTrim();
					if (!"-".equals(supplies)) {
						Building b = DragoStore.getDragoStore().getBuildings()
								.get(pos);
						b.setSuppliesTo(supplies);
						result.add(b.toMap());
					}
				} catch (NumberFormatException e) {
					Log.e(LOG_TAG,
							String.format(
									"Gebäudeposition in Materialansicht konnte nicht geparst werden: %s",
									posStr));
				}
			}
		} catch (JDOMException e) {
			e.printStackTrace();
		}
		return result;
	}

	/**
	 * Lädt Reiter Z und parst den Zustand der Gebäude.
	 * 
	 * @return
	 */
	@SuppressWarnings("unchecked")
	public List<Map<String, String>> getBuildingsWithCondition() {
		List<Map<String, String>> result = new ArrayList<Map<String, String>>();
		try {
			Element root = fetchTab(VILLAGE_CONDITION);
			if (root == null) {
				return result;
			}
			// XMLOutputter out = new XMLOutputter(Format.getPrettyFormat());
			// <tr>
			// <td><a class="inline"
			// href="?t=market&amp;product=alraune">Alraune:</a>&nbsp;</td>
			// <td style="font-size: 10px;">0/0</td>
			// </tr>
			// Finde alle Zeilen mit einem Kindknoten <a class="inline">
			List<Element> res = XPath
					.selectNodes(root,
							"//table[@id='store']/tbody/tr[child::td/child::a[@class='inline']]");
			String condition = "";
			for (Object object : res) {
				Element tr = (Element) object;
				logHtml(tr);
				List<Element> td = tr.getChildren("td");
				// erster Knoten ist <a>
				String posStr = RegexHelper.evalSingleGroupPattern(td.get(0)
						.getChild("a").getAttributeValue("href"),
						posInRequestPattern);
				int pos = -1;
				try {
					pos = Integer.valueOf(posStr);
					Building b = DragoStore.getDragoStore().getBuildings()
							.get(pos);
					if (b != null) {
						// b ist null, für pos=23 = Lager
						// zweiter Knoten ist direkt die Menge
						condition = td.get(1).getTextTrim();
						b.setCondition(condition);
						result.add(b.toMap());
					}
				} catch (NumberFormatException e) {
				}
			}
		} catch (JDOMException e) {
			e.printStackTrace();
		}
		return result;
	}

	/**
	 * Lädt Reiter N und parst die Notizen.
	 * 
	 * @return
	 */
	public CharSequence getNotice() {
		try {
			Element root = fetchTab(VILLAGE_NOTICE);
			if (root == null) {
				return "Fehler beim Lesen der Notizen";
			}
			// XMLOutputter out = new XMLOutputter(Format.getPrettyFormat());
			// <tr>
			// <td><a class="inline"
			// href="?t=market&amp;product=alraune">Alraune:</a>&nbsp;</td>
			// <td style="font-size: 10px;">0/0</td>
			// </tr>
			// Finde alle Zeilen mit einem Kindknoten <a class="inline">
			Element area = (Element) XPath.selectSingleNode(root,
					"//div[@id='mainRight']//form/textarea");
			return area.getText();
		} catch (JDOMException e) {
			e.printStackTrace();
		}
		return "";
	}

	/**
	 * Lädt alle Gebäudenamen, Position und den Tooltip.
	 * 
	 * <div class="pos4 pause progress status " style="width: 100px;"> <div
	 * title="" class="buildingCountdown">1h 35m</div> <div class="tooltip"
	 * id="tooltip4" style="display: none;"> <h3>Steinmetz Stufe 6</h3>
	 * <div>wird ausgebaut.</div> <div></div> </div> </div>
	 */
	@SuppressWarnings("unchecked")
	public List<Map<String, String>> getBuildings() {
		List<Map<String, String>> result = new ArrayList<Map<String, String>>();
		try {
			Element root = fetchTab(VILLAGE_CONDITION);
			if (root == null) {
				return result;
			}
			List<Element> res = XPath
					.selectNodes(root,
							"//div[contains(@class, 'status')]/div[@class = 'tooltip']");
			for (Element div : res) {
				// Parse Position von <div id="tooltip1" class="tooltip"
				// Element tooltipDiv = (Element) XPath.selectSingleNode(div,
				// "./div[@class='tooltip']");
				Building b = new Building(div.getChildTextTrim("h3"));
				int pos = -1;
				try {
					pos = Integer.parseInt(div.getAttributeValue("id")
							.substring(7));
					b.setPosition(pos);
					// Parse Beschreibung
					StringBuilder desc = new StringBuilder();
					List<Element> divs = div.getChildren("div");
					for (Element ele : divs) {
						desc.append(ele.getTextTrim());
					}
					b.setDescription(desc.toString());
					// Parse Typ aus <div
					// class="building pos3 steinbruch "></div>
					Element buildingDiv = (Element) XPath.selectSingleNode(
							root, String.format(
									"//div[contains(@class, 'pos%s ')]", pos));
					for (String clazz : buildingDiv.getAttributeValue("class")
							.split(" ")) {
						try {
							BUILDING_TYPES type = BUILDING_TYPES.valueOf(clazz
									.toUpperCase());
							b.setType(type);
							break;
						} catch (IllegalArgumentException e) {
							// Wirft auf jeden Fall IllegalArgumentException bei
							// Iteration über falsches Class-Attribut
						}
					}
					DragoStore.getDragoStore().getBuildings().put(pos, b);
					if (pos <= 20) {
						result.add(b.toMap());
					}
				} catch (NumberFormatException e) {
					Log.e(DragoidConstants.LOG_TAG,
							"Gebäudeposition konnte nicht geparst werden.");
				}
			}
		} catch (JDOMException e) {
			Log.e(DragoidConstants.LOG_TAG, "Fehler beim Parsen der Gebäude", e);
		}
		return result;
	}

	/**
	 * Prüft, ob der PermanentLogin gültig ist.
	 * 
	 * @param url
	 * @return Fehlermeldung oder null, wenn kein Fehler aufgetreten ist.
	 */
	public static String isValidPermanentLogin(String url) {
		if (url == null) {
			return "Loginurl ist null";
		}
		// TODO Prüfung über Regex
		if (!(url.startsWith("http://www.dragosien.de/?") || url
				.startsWith("http://speed.dragosien.de/"))) {
			return "Loginurl beginnt nicht mit http://www.dragosien.de";
		}
		try {
			@SuppressWarnings("unused")
			URL validUrl = new URL(url);
		} catch (MalformedURLException e) {
			return e.getMessage();
		}
		if (!url.contains("login")) {
			return "Loginurl hat kein Argument login";
		}
		if (!URLUtil.isValidUrl(url)) {
			return "Loginurl ist nicht valide";
		}
		return null;
	}

	private Element fetchTab(int tabId) {
		return fetchUrl(String.format(tabUrl, tabId));
	}

	private Element fetchSingleBuilding(int position) {
		Log.d(LOG_TAG,
				String.format(SINGLEBUILDING_URL, requestToken, position));
		return fetchUrl(String.format(SINGLEBUILDING_URL, requestToken,
				position));
	}

	/**
	 * Lädt eine URL, parst den Userstatus und gibt div#mainContainer zurück
	 * oder null, wenn dabei ein Fehler auftritt.
	 * 
	 * @param url
	 * @return
	 */
	private synchronized Element fetchUrl(String url) {
		try {
			Log.d(LOG_TAG, "Getting " + url);
			HtmlCleaner cleaner = new HtmlCleaner();
			CleanerProperties props = cleaner.getProperties();
			props.setOmitComments(true);
			props.setAllowHtmlInsideAttributes(true);
			TagNode root;
			HttpGet get = new HttpGet(url);
			ResponseHandler<String> responseHandler = new BasicResponseHandler();
			String responseBody = client.execute(get, responseHandler);

			// Wir durchsuchen die script-tags nach dem Requesttoken
			searchRequestToken(responseBody);
			root = cleaner.clean(responseBody);
			// Uns interessiert nur der Hauptteil, der ganze rest muss nicht
			// nach
			// JDOM überführt werden
			TagNode mainContainer = null;

			Object[] divs = root.evaluateXPath("//div[@class='mainContainer']");
			// Sollte genau eins sein
			if (divs == null || divs.length != 1
					|| !(divs[0] instanceof TagNode)) {
				Log.e(LOG_TAG,
						"Seite konnte nicht geladen werden. div#mainContainer wurde nicht gefunden.");
				return null;
			}
			mainContainer = (TagNode) divs[0];
			JDomSerializer ser = new JDomSerializer(cleaner.getProperties());
			Document doc = ser.createJDom(mainContainer);
			// parsing user info
			Element div = (Element) XPath.selectSingleNode(doc,
					"//div[@id='userinfo']");
			DragoStore.getDragoStore().getUserInfo().parseUserStatus(div);
			return doc.getRootElement();
		} catch (IllegalArgumentException e) {
			Log.e(LOG_TAG, "Seite konnte nicht geladen werden.", e);
		} catch (XPatherException e) {
			Log.e(LOG_TAG,
					"Seite konnte nicht geladen werden. Fehler beim XPathen des MainContainers",
					e);
		} catch (JDOMException e) {
			Log.e(LOG_TAG,
					"Seite konnte nicht geladen werden. Fehler beim Parsen des MainContainers durch JDOM",
					e);
		} catch (IOException e) {
			Log.e(LOG_TAG, "Seite konnte nicht geladen werden. IOException", e);
		}
		return null;
	}

	/**
	 * Liest die Informationen eines einzelnen Gebäudes.
	 * 
	 * @param pos
	 *            Position des Gebäudes.
	 */
	public void updateSingleBuilding(int pos) {
		Building b = DragoStore.getDragoStore().getBuildings().get(pos);
		if (b == null) {
			Log.e(LOG_TAG, "Einzelgebäude konnte nicht geladen werden");
			return;
		}
		Element root;

		root = fetchSingleBuilding(pos);
		updateSingleBuilding(root, b);
	}

	@SuppressWarnings("unchecked")
	private void updateSingleBuilding(Element root, Building b) {
		try {
			try {
				// Update Zustand
				Element condition = (Element) XPath.selectSingleNode(root,
						"//div[@class='layer_box']/div/span");
				b.setCondition(condition.getTextTrim());
			} catch (NullPointerException e) {
			}
			try {
				// Setze Renovierungskosten
				Element renovationCosts = (Element) XPath.selectSingleNode(
						root, "//div[@id='cost_renovate']");
				StringBuilder costsStr = new StringBuilder();
				for (Object ele : renovationCosts.getContent()) {
					costsStr.append(((Content) ele).getValue().trim());
				}
				b.setRenovateCosts(costsStr.toString());
			} catch (NullPointerException e) {
			}
			try {
				// Was wird durch dieses Gebäude erforscht?
				List<Content> develops = (List<Content>) XPath
						.selectNodes(root,
								"//div[@id='cost_renovate']/following-sibling::*|text()");
				StringBuilder devStr = new StringBuilder("Erforscht ");
				for (Content ele : develops) {
					devStr.append(ele.getValue().trim());
				}
				b.setDevelops(devStr.toString());
			} catch (NullPointerException e) {
			}
			// Lese Material
			b.getMaterial().clear();
			List<Element> ths = (List<Element>) XPath.selectNodes(root,
					"//th[contains(@id, 'building_material')]");
			for (Element th : ths) {
				BuildingMaterial bm = new BuildingMaterial();
				try {
					String needStr = th.getChildText("b").split(" ")[1];
					bm.setNeeds(Integer.parseInt(needStr));
				} catch (NumberFormatException e) {
					Log.e(LOG_TAG,
							"Benötigte Warenanzahl konnte nicht ermittelt werden: "
									+ th.getChildText("b"), e);
				}
				/*
				 * <td> 1.002 <a class="inline"
				 * href="?t=market&amp;product=holz">Holz</a> vor Ort (reicht
				 * bis <span id="building_material1_until">02.02.2011
				 * 10:47</span>) <a
				 * onclick="getbackMaterial(7, 'holz');return false;"
				 * href="http://www.dragosien.de/?&amp;t=building&amp;position=7"
				 * >[zurückziehen]</a> </td>
				 */
				Element hasTd = (Element) XPath.selectSingleNode(th,
						"../following-sibling::tr/td[1]");
				int has = 0;
				try {
					String hasText = hasTd.getTextTrim();
					has = Integer.valueOf(hasText.split(" ")[0]
							.replace(".", ""));
				} catch (NumberFormatException e) {
					// Ist kein Fehler, wenn kein Material vorhanden ist.
					has = 0;
				} catch (ArrayIndexOutOfBoundsException e) {
					Log.d(LOG_TAG,
							"Bereitgestellte Materialien konnten nicht geparst werden.",
							e);
				}
				bm.setHas(has);
				Attribute value = (Attribute) XPath.selectSingleNode(th,
						"../following-sibling::tr/td/input/@value");
				bm.setValue(value.getIntValue());
				Attribute id = (Attribute) XPath.selectSingleNode(th,
						"../following-sibling::tr/td/input/@id");
				bm.setStockType(id.getValue().substring(7));
				b.getMaterial().add(bm);
			}

			// Lese Auf- und Umbau
			// Selektiere alle Tabellenreihen mit Ausbaukosten
			b.getUpgrades().clear();
			List<Element> tableRows = (List<Element>) XPath
					.selectNodes(root,
							"//div[@class='layer_box']/div/table//tr[./td[@id='building_upgrade_cost']]");
			for (Iterator<Element> it = tableRows.iterator(); it.hasNext();) {
				BuildingUpgrade upgrade = parseUpgrade(it);
				upgrade.setUpgrade(true);
				b.getUpgrades().add(upgrade);
			}
			// Und das gleiche für Tabellenreihen mit Umbaukosten
			tableRows = (List<Element>) XPath
					.selectNodes(
							root,
							"//div[@class='layer_box']/div/table//tr[./td[contains(@id, 'building_reconstruct_cost')]]");
			for (Iterator<Element> it = tableRows.iterator(); it.hasNext();) {
				BuildingUpgrade upgrade = parseUpgrade(it);
				upgrade.setUpgrade(false);
				b.getUpgrades().add(upgrade);
			}
		} catch (JDOMException e) {
			Log.e(LOG_TAG, "Einzelgebäude konnte nicht geparst werden", e);
		}
	}

	private BuildingUpgrade parseUpgrade(Iterator<Element> it)
			throws JDOMException {
		Element row = it.next();
		// logHtml(row);
		BuildingUpgrade bu = new BuildingUpgrade();
		// // Hier parsen wir jetzt die ganzen Informationen
		@SuppressWarnings("unchecked")
		List<Element> tds = row.getChildren("td");
		// Name unterscheidet sich je nach Ausbau/Umbau
		bu.setName(tds.get(1).getValue().trim());
		bu.setProduces(RegexHelper.removeTags(tds.get(2).getValue()));
		bu.setRequirementStock(tds.get(4).getValue().trim());
		bu.setBuildingtime(tds.get(5).getTextTrim());
		// Fehlende Materialien befinden sich in der nächsten Zeile
		Element sibling = (Element) XPath.selectSingleNode(row,
				"following-sibling::tr[1]/td");
		if (sibling != null) {
			bu.setMissingStock(sibling.getValue().trim());
			// Wenn im Text das Wort "fehlt" vorkommt, kann noch nicht ausgebaut
			// werden.
			bu.setPrepared(!bu.getMissingStock().contains("fehl"));
		}
		return bu;
	}

	/**
	 * Füllt die Materialien eines Gebäudes wieder auf.
	 * 
	 * @param position
	 * @param value
	 * @param type
	 */
	public void transferMaterial(int position, int value, STOCK_TYPE type) {
		Log.d(LOG_TAG, String.format("pos=%s, value=%s, type=%s", position,
				value, type));
		Building b = DragoStore.getDragoStore().getBuildings().get(position);
		if (b == null) {
			Log.e(LOG_TAG, "Einzelgebäude konnte nicht geladen werden");
			return;
		}
		Element root;
		root = fetchUrl(String.format(TRANSFER_MATERIAL_URL, requestToken,
				position, type.name().toLowerCase(), value));
		if (root != null) {
			updateSingleBuilding(root, b);
		}
	}

	/**
	 * Zieht die Materialien eines Gebäudes zurück.
	 * 
	 * @param position
	 *            Gebäudeposition
	 * @param type
	 *            Ware
	 */
	public void getBackMaterial(int position, STOCK_TYPE type) {
		Log.d(LOG_TAG, String.format("pos=%s, type=%s", position, type));
		Building b = DragoStore.getDragoStore().getBuildings().get(position);
		if (b == null) {
			Log.e(LOG_TAG, "Einzelgebäude konnte nicht geladen werden");
			return;
		}
		Element root;
		root = fetchUrl(String.format(WITHDRAW_MATERIAL_URL, requestToken,
				position, type.name().toLowerCase()));
		if (root != null) {
			updateSingleBuilding(root, b);
		}
	}

	/**
	 * Benutzt einen REGEX um den Requesttoken zu ermitteln, der bei jeder
	 * Anfrage übertragen werden muss. TODO Muss das wirklich noch sein, nachem
	 * wir jetzt die Cookies drin haben?
	 * 
	 * @param html
	 */
	private void searchRequestToken(String html) {
		String tmp = RegexHelper.evalSingleGroupPattern(html, requestPattern);
		if (tmp != null) {
			requestToken = tmp;
			return;
		}
		Log.d(LOG_TAG, "Requesttoken nicht gefunden in" + html);
	}

	private void logHtml(Element ele) {
		if (ele == null) {
			Log.d(LOG_TAG, "Zu loggendes Element ist null");
		} else if (!(ele instanceof Element)) {
			Log.d(LOG_TAG, "Zu loggendes Element ist kein Element sondern "
					+ ele);
		} else {
			Log.d(LOG_TAG,
					String.format("#### START LOGGING ELEMENT %s ####",
							ele.getName()));
			StringWriter writer = new StringWriter();
			XMLOutputter out = new XMLOutputter(Format.getPrettyFormat());
			try {
				out.output(ele, writer);
				String[] strings = writer.toString().split("\\n");
				for (String string : strings) {
					Log.d(LOG_TAG, string);
				}

			} catch (IOException e) {
			}
			Log.d(LOG_TAG,
					String.format("#### ENDE LOGGING ELEMENT %s ####",
							ele.getName()));
		}
	}

	/**
	 * Startet den Aus- oder Umbau eines Gebäudes und liest die Informationen
	 * anschließend neu ein.
	 * 
	 * @param building
	 * @param bu
	 */
	public void upgradeBuilding(Building building, BuildingUpgrade bu) {
		if (building == null || bu == null
				|| !building.getUpgrades().contains(bu)) {
			Log.e(LOG_TAG, String.format(
					"Upgrade ist ungültig building=%s, bu=%s", building, bu));
			return;
		}
		Log.d(LOG_TAG, String.format(
				"upgradeBuilding building=%s, new building=%s",
				building.getName(), bu.getName()));
		Element root;
		root = fetchUrl(String.format(UPGRADE_BUILDING_URL, requestToken,
				building.getPosition(), bu.getActionStr()));
		if (root != null) {
			updateSingleBuilding(root, building);
		}
	}

	public static String getLastError() {
		return lastError;
	}
}
